{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "cf248643-1102-4ad0-b5f9-f9411143abda",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>positionName</th>\n",
       "      <th>skill_list</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>算法工程师</td>\n",
       "      <td>[r, c, 自动化, 仿真, ros]</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>算法工程师</td>\n",
       "      <td>[python, 算法, r, 数据挖掘, hive, c, java, hadoop, 模...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>算法工程师</td>\n",
       "      <td>[python, 算法, r, linux, scala, 数据处理, 序列, sklear...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>算法工程师</td>\n",
       "      <td>[python, 算法, learn, r, 数据挖掘, 建模, lr, ai, 模型, s...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>算法工程师</td>\n",
       "      <td>[web, waf, torch, r, 数据挖掘, 建模, 测试工具, mxnet, ca...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  positionName                                         skill_list\n",
       "0        算法工程师                               [r, c, 自动化, 仿真, ros]\n",
       "1        算法工程师  [python, 算法, r, 数据挖掘, hive, c, java, hadoop, 模...\n",
       "2        算法工程师  [python, 算法, r, linux, scala, 数据处理, 序列, sklear...\n",
       "3        算法工程师  [python, 算法, learn, r, 数据挖掘, 建模, lr, ai, 模型, s...\n",
       "4        算法工程师  [web, waf, torch, r, 数据挖掘, 建模, 测试工具, mxnet, ca..."
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "import jieba\n",
    "import re\n",
    "\n",
    "# ====== 加载技术词汇并预处理 ======\n",
    "with open(\"skill.txt\", \"r\", encoding=\"utf-8\") as f:\n",
    "    raw_skills = f.read().strip().split(\",\")\n",
    "    \n",
    "# 初始化多级词典和最大长度\n",
    "tech_tree = {}\n",
    "max_word_length = 0\n",
    "for word in raw_skills:\n",
    "    # 处理词汇并计算长度\n",
    "    clean_word = word.lower().strip().replace(' ', '')  # 移除空格\n",
    "    word_length = len(clean_word)\n",
    "    \n",
    "    # 更新最大长度\n",
    "    max_word_length = max(max_word_length, word_length)\n",
    "    \n",
    "    # 构建多级词典\n",
    "    if word_length not in tech_tree:\n",
    "        tech_tree[word_length] = set()\n",
    "    tech_tree[word_length].add(clean_word)\n",
    "    \n",
    "# 添加缩写映射（直接添加目标词汇）\n",
    "additional_skills = {'javascript', 'python'}  # 确保映射目标存在\n",
    "for word in additional_skills:\n",
    "    word_length = len(word)\n",
    "    if word_length not in tech_tree:\n",
    "        tech_tree[word_length] = set()\n",
    "    tech_tree[word_length].add(word)\n",
    "\n",
    "# ====== 定义技术抽取函数 ======\n",
    "def extract_skills(text):\n",
    "    if pd.isna(text):\n",
    "        return []\n",
    "    # 文本清洗\n",
    "    text = re.sub(r'[\\.\\d\\+\\-]', ' ', text.lower())  # 移除版本号\n",
    "    text = re.sub(r'\\s+', ' ', text).strip()  # 合并空格\n",
    "    \n",
    "    found_skills = set()\n",
    "    n = len(text)\n",
    "    i = 0\n",
    "    \n",
    "    while i < n:\n",
    "        # 跳过无效字符\n",
    "        if not text[i].isalnum() and not ('\\u4e00' <= text[i] <= '\\u9fff'):\n",
    "            i += 1\n",
    "            continue\n",
    "        \n",
    "        # 动态计算最大匹配长度\n",
    "        current_max_len = min(n - i, max_word_length)\n",
    "        matched = False\n",
    "        \n",
    "        # 从长到短尝试匹配\n",
    "        for length in range(current_max_len, 0, -1):\n",
    "            if length not in tech_tree:\n",
    "                continue  # 无此长度的词汇\n",
    "            \n",
    "            candidate = text[i:i+length]\n",
    "            if candidate in tech_tree[length]:\n",
    "                found_skills.add(candidate)\n",
    "                i += length\n",
    "                matched = True\n",
    "                break\n",
    "        \n",
    "        if not matched:\n",
    "            i += 1  # 未找到匹配项\n",
    "    \n",
    "    return list(found_skills)\n",
    "\n",
    "# ====== 应用函数并展示结果 ======\n",
    "df = pd.read_csv(\"拉勾网2023招聘数据.csv\")\n",
    "df[\"skill_list\"] = df[\"positionDetail\"].apply(extract_skills)\n",
    "df[[\"positionName\", \"skill_list\"]].head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "4b2644d4-56e3-427b-9aa2-041404134336",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- 调整关联规则参数 ---\n",
    "from mlxtend.preprocessing import TransactionEncoder\n",
    "from mlxtend.frequent_patterns import apriori, association_rules\n",
    "import pickle\n",
    "\n",
    "# 步骤1：将二维列表转换为独热编码DataFrame\n",
    "te = TransactionEncoder()\n",
    "te_ary = te.fit(df[\"skill_list\"]).transform(df[\"skill_list\"])\n",
    "df_encoded = pd.DataFrame(te_ary, columns=te.columns_)\n",
    "\n",
    "# 步骤2：计算频繁项集（支持度调整为0.02，减少噪声）\n",
    "frequent_itemsets = apriori(df_encoded, min_support=0.02, use_colnames=True)\n",
    "\n",
    "# 步骤3：计算关联规则（置信度调整为0.6，提升相关性）\n",
    "rules = association_rules(frequent_itemsets, metric=\"confidence\", min_threshold=0.6)\n",
    "\n",
    "# 步骤4：保存结果（实验步骤3）\n",
    "with open(\"apriori.bin\", \"wb\") as f:\n",
    "    pickle.dump({\"frequent_itemsets\": frequent_itemsets, \"rules\": rules}, f)\n",
    "\n",
    "def load_apriori(filepath):\n",
    "    with open(filepath, \"rb\") as f:\n",
    "        return pickle.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "43178311-7a0b-41f0-b570-a729a354d83a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# --- 调整关联规则参数 ---\n",
    "from mlxtend.preprocessing import TransactionEncoder\n",
    "from mlxtend.frequent_patterns import apriori, association_rules\n",
    "import pickle\n",
    "\n",
    "# 步骤1：将二维列表转换为独热编码DataFrame\n",
    "te = TransactionEncoder()\n",
    "te_ary = te.fit(df[\"skill_list\"]).transform(df[\"skill_list\"])\n",
    "df_encoded = pd.DataFrame(te_ary, columns=te.columns_)\n",
    "\n",
    "# 步骤2：计算频繁项集（支持度调整为0.02，减少噪声）\n",
    "frequent_itemsets = apriori(df_encoded, min_support=0.02, use_colnames=True)\n",
    "\n",
    "# 步骤3：计算关联规则（置信度调整为0.6，提升相关性）\n",
    "rules = association_rules(frequent_itemsets, metric=\"confidence\", min_threshold=0.6)\n",
    "\n",
    "# 步骤4：保存结果（实验步骤3）\n",
    "with open(\"apriori.bin\", \"wb\") as f:\n",
    "    pickle.dump({\"frequent_itemsets\": frequent_itemsets, \"rules\": rules}, f)\n",
    "\n",
    "def load_apriori(filepath):\n",
    "    with open(filepath, \"rb\") as f:\n",
    "        return pickle.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "a4c80044-f11e-4094-ac9d-a44cf038014f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ====== 增强的关联规则查询 ======\n",
    "def get_associated_skills(apriori_data, target_skill):\n",
    "    \"\"\"查询与目标技术关联的其他技术\"\"\"\n",
    "    target_skill = target_skill.lower()\n",
    "    # 筛选包含目标技术的前件规则\n",
    "    filtered_rules = apriori_data[\"rules\"][\n",
    "        apriori_data[\"rules\"][\"antecedents\"].apply(lambda x: target_skill in x)\n",
    "    ]\n",
    "    # 按支持度过滤并提取后件技术\n",
    "    associated_skills = list(filtered_rules[\"consequents\"].explode().unique())[:5]  # 只返回前5个热门技术\n",
    "    return associated_skills\n",
    "\n",
    "# ====== 岗位技能查询优化 ======\n",
    "def get_position_skills(position_name):\n",
    "    \"\"\"查询某岗位需要掌握的核心技术\"\"\"\n",
    "    # 筛选该岗位的所有skill_list\n",
    "    position_skills = df[df[\"positionName\"] == position_name][\"skill_list\"]\n",
    "    # 统计技术出现频率（取前5）\n",
    "    freq = pd.Series([skill for sublist in position_skills for skill in sublist]).value_counts().head(5)\n",
    "    return freq.index.tolist()\n",
    "\n",
    "# ====== 技术岗位匹配优化 ======\n",
    "def get_suitable_positions(target_skill):\n",
    "    \"\"\"查询掌握某技术适合的岗位\"\"\"\n",
    "    skill = target_skill.lower()\n",
    "    # 筛选包含该技术的岗位\n",
    "    suitable_positions = df[df[\"skill_list\"].apply(lambda x: skill in x)][\"positionName\"]\n",
    "    # 统计岗位出现频率（取前5）\n",
    "    return suitable_positions.value_counts().head(5).index.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "9c8f5b0a-e565-4fd5-ac23-e5914321916e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "测试关联技术推荐:\n",
      "1. 调用的函数是 `recommend_associated_skills`，它接受一个参数 `skill`，我们传递的值是 `'java'`。这个函数的目的是根据给定的技能（在这个案例中是Java），推荐与之相关的其他技能。\n",
      "\n",
      "2. 返回结果 `['r', 'c', 'mysql', 'spring', 'html']` 表示的是与Java技能相关的其他技能。这意味着如果你掌握了Java，那么以下技能也很值得学习或掌握：R语言、C语言、MySQL数据库、Spring框架和HTML。\n",
      "\n",
      "3. 针对这个结果，以下是我的专业建议：\n",
      "   - 学习R语言可以帮助你更好地进行数据分析和统计建模，这在数据科学领域与Java结合使用时特别有用。\n",
      "   - C语言作为一门基础编程语言，能够帮助你理解计算机的底层工作原理，提高程序的运行效率。\n",
      "   - MySQL是一个广泛使用的数据库管理系统，学会它可以帮助你处理和存储Java应用程序的数据。\n",
      "   - Spring框架是Java开发中非常流行的企业级应用开发框架，掌握它能够帮助你更高效地开发复杂的企业级应用。\n",
      "   - HTML是网页开发的基础，如果你想要用Java开发Web应用，那么了解HTML是必要的，它可以帮助你构建用户界面。\n",
      "\n",
      "综上所述，掌握这些相关技能可以让你在Java开发领域更加全面和高效。\n",
      "\n",
      "测试岗位技能查询:\n",
      "1. 说明调用的函数及其参数：\n",
      "   我们调用的函数是 `get_position_required_skills`，这个函数的作用是获取某个职位所需的技能。在这个调用中，我们传递的参数是 `position`，其值为 `'算法工程师'`，表示我们想要了解成为一名算法工程师所需要具备的技能。\n",
      "\n",
      "2. 解释返回结果的含义：\n",
      "   函数返回的结果是一个列表，包含 `'算法'`、`'c'`、`'python'`、`'r'` 和 `'深度学习'` 五个元素。这意味着，根据这个函数的查询结果，想要成为一名算法工程师，你至少需要掌握以下技能：算法知识、C语言、Python语言、R语言以及深度学习的相关知识和技能。\n",
      "\n",
      "3. 给出专业建议：\n",
      "   如果你想成为一名算法工程师，我建议你专注于以下几个方面的技能提升：\n",
      "   - **算法知识**：深入理解常见的数据结构和算法，这是基础中的基础。\n",
      "   - **编程语言**：熟练掌握C语言、Python和R语言，这些语言在算法开发中应用广泛，C语言适合进行性能优化，而Python和R在数据分析、机器学习等领域非常流行。\n",
      "   - **深度学习**：了解并掌握深度学习的基本原理和框架，如TensorFlow或PyTorch，这对于处理复杂的数据问题和开发智能模型至关重要。\n",
      "   - **实践经验**：通过实际项目或开源项目来应用你的知识，实践是检验学习成果的最佳方式。\n",
      "   - **持续学习**：技术是不断进步的，保持好奇心和学习的热情，跟上最新的技术趋势和算法研究。\n",
      "\n",
      "遵循以上建议，将有助于你在算法工程师的职位上取得成功。\n",
      "\n",
      "测试适合岗位推荐:\n",
      "1. 我们调用的函数是 `find_suitable_positions`，这个函数的作用是寻找与特定技能相关的职位。在这个调用中，我们传递的参数是 `skill='Java'`，即我们要寻找与Java技能相匹配的职业岗位。\n",
      "\n",
      "2. 返回的结果是一个列表，包含了与Java技能相关的多个职位。这些职位包括：\n",
      "   - Java工程师\n",
      "   - 大数据/数据分析工程师\n",
      "   - 移动开发工程师\n",
      "   - 算法工程师\n",
      "   - 前端开发工程师\n",
      "   这个列表意味着如果你掌握了Java技能，你可能会适合上述任何一个职位。\n",
      "\n",
      "3. 针对这个查询结果，以下是我的专业建议：\n",
      "   - Java作为一门广泛使用的编程语言，其相关职位市场需求量大，你可以根据个人兴趣和职业规划进行选择。\n",
      "   - 如果你对开发后端系统感兴趣，可以考虑成为Java工程师。\n",
      "   - 如果你对处理和分析大量数据感兴趣，那么大数据/数据分析工程师可能是一个不错的选择。\n",
      "   - 如果你喜欢移动应用开发，移动开发工程师可能适合你。\n",
      "   - 如果你对算法和数学模型有浓厚的兴趣，那么算法工程师可能是一个很好的职业路径。\n",
      "   - 如果你对用户界面和用户体验设计感兴趣，前端开发工程师会是一个合适的选择。\n",
      "   - 在决定职业方向时，建议考虑个人的技能水平、职业兴趣以及行业发展趋势，同时也要关注职位的长期发展潜力和个人职业成长。不妨多参加一些相关的技术交流，了解各个职位的具体工作内容和行业需求，以便做出更明智的决策。\n"
     ]
    }
   ],
   "source": [
    "from zhipuai import ZhipuAI\n",
    "import json\n",
    "\n",
    "# 加载预计算的关联规则数据\n",
    "apriori_data = load_apriori(\"apriori.bin\")\n",
    "\n",
    "# 定义工具列表（LLM自动选择）\n",
    "tools = [\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"recommend_associated_skills\",\n",
    "            \"description\": \"根据用户擅长的技术，推荐关联的其他技术\",\n",
    "            \"parameters\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                    \"skill\": {\n",
    "                        \"type\": \"string\",\n",
    "                        \"description\": \"用户擅长的技术名称（如：java）\"\n",
    "                    }\n",
    "                },\n",
    "                \"required\": [\"skill\"]\n",
    "            }\n",
    "        }\n",
    "    },\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"get_position_required_skills\",\n",
    "            \"description\": \"查询某岗位需要掌握的核心技术\",\n",
    "            \"parameters\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                    \"position\": {\n",
    "                        \"type\": \"string\",\n",
    "                        \"description\": \"目标岗位名称（如：算法工程师）\"\n",
    "                    }\n",
    "                },\n",
    "                \"required\": [\"position\"]\n",
    "            }\n",
    "        }\n",
    "    },\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"find_suitable_positions\",\n",
    "            \"description\": \"根据用户掌握的技术，推荐适合的岗位\",\n",
    "            \"parameters\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                    \"skill\": {\n",
    "                        \"type\": \"string\",\n",
    "                        \"description\": \"用户掌握的技术名称（如：python）\"\n",
    "                    }\n",
    "                },\n",
    "                \"required\": [\"skill\"]\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "]\n",
    "\n",
    "# 创建工具描述字典，方便后续查询\n",
    "tool_descriptions = {\n",
    "    tool[\"function\"][\"name\"]: tool[\"function\"][\"description\"]\n",
    "    for tool in tools\n",
    "}\n",
    "\n",
    "def process_user_question(question):\n",
    "    client = ZhipuAI(api_key=\"3648d03d25a9440088e907b567714673.E4f7jmIL4bwpS9lw\")  # 您需要替换为您的API密钥\n",
    "    messages = [{\"role\": \"user\", \"content\": question}]\n",
    "    \n",
    "    try:\n",
    "        # 第一步：识别用户意图\n",
    "        response = client.chat.completions.create(\n",
    "            model=\"glm-4\",\n",
    "            messages=messages,\n",
    "            tools=tools,\n",
    "            tool_choice=\"auto\"\n",
    "        )\n",
    "        message = response.choices[0].message\n",
    "        \n",
    "        if not hasattr(message, \"tool_calls\"):\n",
    "            return \"未能识别有效问题类型，请尝试以下提问方式：\\n1. 我擅长XX技术，应该学习什么？\\n2. XX岗位需要哪些技能？\\n3. 我会XX技术，适合什么岗位？\"\n",
    "\n",
    "        # 第二步：执行对应函数\n",
    "        tool_call = message.tool_calls[0]\n",
    "        func_name = tool_call.function.name\n",
    "        params = json.loads(tool_call.function.arguments)\n",
    "        \n",
    "        # 获取参数名和值\n",
    "        param_name = list(params.keys())[0]\n",
    "        param_value = params[param_name]\n",
    "        \n",
    "        # 根据函数名调用对应函数\n",
    "        if func_name == \"recommend_associated_skills\":\n",
    "            raw_result = get_associated_skills(apriori_data, param_value)\n",
    "        elif func_name == \"get_position_required_skills\":\n",
    "            raw_result = get_position_skills(param_value)\n",
    "        elif func_name == \"find_suitable_positions\":\n",
    "            raw_result = get_suitable_positions(param_value)\n",
    "        \n",
    "        # 第三步：生成自然语言回答\n",
    "        prompt = f\"\"\"\n",
    "        ##### 函数调用追踪 #####\n",
    "        调用的函数: {func_name}({param_name}='{param_value}')\n",
    "        返回结果: {raw_result}\n",
    "        ######################\n",
    "        \n",
    "        请根据以上函数调用结果生成自然语言回答：\n",
    "        1. 说明调用的函数及其参数\n",
    "        2. 解释返回结果的含义\n",
    "        3. 给出专业建议\n",
    "        \"\"\"\n",
    "        \n",
    "        final_response = client.chat.completions.create(\n",
    "            model=\"glm-4\",\n",
    "            messages=[{\"role\": \"user\", \"content\": prompt}],\n",
    "            temperature=0.3\n",
    "        )\n",
    "        return final_response.choices[0].message.content\n",
    "        \n",
    "    except Exception as e:\n",
    "        error_msg = f\"\"\"\n",
    "        ⚠️ 服务暂时不可用，请稍后重试\n",
    "        --------------------------\n",
    "        错误类型：{type(e).__name__}\n",
    "        错误信息：{str(e)}\n",
    "        \"\"\"\n",
    "        return error_msg\n",
    "\n",
    "# ====== 验证测试 ======\n",
    "if __name__ == \"__main__\":\n",
    "    # 测试关联技术推荐\n",
    "    print(\"测试关联技术推荐:\")\n",
    "    print(process_user_question(\"我比较擅长Java，应该学习什么其他技术？\"))\n",
    "    \n",
    "    # 测试岗位技能查询\n",
    "    print(\"\\n测试岗位技能查询:\")\n",
    "    print(process_user_question(\"算法工程师这个岗位需要学什么技术？\"))\n",
    "    \n",
    "    # 测试适合岗位推荐\n",
    "    print(\"\\n测试适合岗位推荐:\")\n",
    "    print(process_user_question(\"我会Java，适合什么岗位？\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c368e168-e9b7-4962-9822-35140b6bfb54",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
